<?php

	namespace org\tekuna\framework\component;

	use \Exception;

	use org\tekuna\core\application\Application;
	use org\tekuna\core\context\Context;
	use org\tekuna\core\configuration\ConfigurationElement;

	use org\tekuna\framework\RequestDispatchException;
	use org\tekuna\framework\request\Request;

	
	/**
	 * This class processes an incoming CLI request and matches the component
	 * that holds further action definitions. The component is matched
	 * by the calling script name (first argument of command line)
	 */
	class CliComponentProcessor {

		private
			$objContext = NULL,
			$arrComponents = array();


		/**
		 * Construct a new CliComponentProcessor
		 * 
		 * @param Context $objContext the application context
		 */
		public function __construct(Context $objContext) {

			$this -> objContext = $objContext;

			// TODO: some validation of the configured components
			$objParentElement = $objContext -> getConfiguration() -> getRootElement();
			$this -> arrComponents = $objParentElement -> getAllChildElements('framework', 'cli-component');
		}


		/**
		 * This method runs the matching process against all declared
		 * components and returns the first matching component configuration element.
		 * 
		 * @return ConfigurationElement the matched component configuration element
		 * @throws ComponentException if anything goes wrong
		 * @throws RequestDispatchException when no matching component was found
		 */
		public function getMatchingCliComponent() {

			foreach ($this -> arrComponents as $objComponent) {

				try {

					if ($this -> isMatchingCliComponent($objComponent)) {

						return $objComponent;
					}
				}
				catch (Exception $objException) {

					throw new ComponentException("Error while matching CLI component ". trim($objComponent -> __toString()), -1, $objException);
				}
			}

			throw new RequestDispatchException("No matching CLI component found.");
		}

		
		protected function isMatchingCliComponent(ConfigurationElement $objElement) {

			$objRequest = $this -> objContext -> getRequest();
			
			// special matching applies when less than 3 parameters are given
			if ($objRequest -> getArgumentCount() < 3) {
				
				return ! $objElement -> hasAttribute('framework', 'first-param');
			}
			else {
			
				// component without that parameter can't match
				if (! $objElement -> hasAttribute('framework', 'first-param')) {
					
					return false;
				}
				
				// get the first command line param
				$sFirstParam = $objRequest -> getArgument(1);
	
				// get the component's first-param attribute
				$sComponentFirstParam = $objElement -> getAttribute('framework', 'first-param') -> getValue();
	
				return trim($sFirstParam) === trim($sComponentFirstParam);
			}
		}
	}

